package at.tuwien.seminar.scrum1.provider;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;

/**
 * Generic Wicket Data Provider
 * 
 * @author KimmelF
 */
public class DataProvider<T> extends SortableDataProvider<T> {

	/**
	 * Serial ID
	 */
	private static final long serialVersionUID = 1L;
	/**
	 * Actual Data
	 */
	List<T> list = new ArrayList<T>();

	/**
	 * Constructor. Load Data
	 * 
	 * @param initialList
	 *            Initial List
	 * @param defaultSort
	 *            Default Sort Row
	 */
	public DataProvider(String defaultSort, List<T> initialList) {

		init(defaultSort, true, initialList);
	}

	private void init(String defaultSort, boolean ascending, List<T> initialList) {
		setSort(defaultSort, ascending);
		list.addAll(initialList);
	}

	/**
	 * @param first
	 *            First Element to Start With
	 * @param count
	 *            Number of Elements
	 * @return Iterator of the new Sorted List
	 */
	public Iterator<T> iterator(int first, int count) {

		List<T> newList = new ArrayList<T>();
		final String sortColumn = this.getSort().getProperty();
		final boolean ascending = this.getSort().isAscending();

		Collections.sort(list, new Comparator<Object>() {

			public int compare(Object obj1, Object obj2) {

				PropertyModel<Object> model1 = new PropertyModel<Object>(obj1,
						sortColumn);
				PropertyModel<Object> model2 = new PropertyModel<Object>(obj2,
						sortColumn);

				Object modelObject1 = model1.getObject();
				Object modelObject2 = model2.getObject();

				int compare = 0;
				if ((modelObject1 == null && modelObject2 != null)) {
					compare = 1;
				} else if ((modelObject1 != null && modelObject2 == null)) {
					compare = -1;
				} else if (modelObject1 == null && modelObject2 == null) {
					compare = 0;
				} else {
					if (modelObject1 instanceof Comparable
							&& modelObject2 instanceof Comparable) {
						compare = ((Comparable<Object>) modelObject1)
								.compareTo(modelObject2);
					} else {
						compare = 0;
					}
				}

				if (!ascending) {
					compare *= -1;
				}

				return compare;
			}
		});

		newList.addAll(list.subList(first, first + count));
		return newList.iterator();
	}

	/**
	 * Size of the List
	 * 
	 * @return Size
	 */
	public int size() {

		return list.size();
	}

	/**
	 * @param object
	 *            Object
	 * @return Object as IModel
	 */
	public IModel<T> model(final Object object) {

		return new AbstractReadOnlyModel<T>() {

			/**
			 * Serial ID
			 */
			private static final long serialVersionUID = 1L;

			@SuppressWarnings("unchecked")
			@Override
			public T getObject() {

				return (T) object;
			}
		};
	}
}
